<!DOCTYPE html>
<html>
  <head><meta name="generator" content="Hexo 3.8.0">
  <meta http-equiv="content-type" content="text/html; charset=utf-8">
  <meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" name="viewport">
  <meta name="description" content="fengzhaoyang&#39;s blog">
  <meta name="keyword" content="hexo-theme, vuejs">
  
  <link rel="shortcut icon" href="/css/images/logo.png">
  
  <title>
    
    大型网站技术架构 | fzy-blog
    
  </title>
  <link href="//cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">
  <link href="//cdnjs.cloudflare.com/ajax/libs/nprogress/0.2.0/nprogress.min.css" rel="stylesheet">
  <link href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/tomorrow.min.css" rel="stylesheet">
  <link rel="stylesheet" href="/css/style.css">
  
  <script src="//cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
  <script src="//cdnjs.cloudflare.com/ajax/libs/geopattern/1.2.3/js/geopattern.min.js"></script>
  <script src="//cdnjs.cloudflare.com/ajax/libs/nprogress/0.2.0/nprogress.min.js"></script>
  
  <script src="/js/qrious.js"></script>
  
  
  
  
    <!-- MathJax support START -->
    <script type="text/x-mathjax-config">
      MathJax.Hub.Config({
        tex2jax: {
          inlineMath: [ ['$','$'], ["\\(","\\)"]  ],
          processEscapes: true,
          skipTags: ['script', 'noscript', 'style', 'textarea', 'pre', 'code']
        }
      });
    </script>

    <script type="text/x-mathjax-config">
      MathJax.Hub.Queue(function() {
        var all = MathJax.Hub.getAllJax(), i;
        for (i=0; i < all.length; i += 1) {
          all[i].SourceElement().parentNode.className += ' has-jax';
        }
      });
    </script>
    <script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
    <!-- MathJax support END -->
  


</head>
<div class="wechat-share">
  <img src="/css/images/logo.png">
</div>
  <body>
    <header class="header fixed-header">
  <div class="header-container">
    <a class="home-link" href="/">
      <div class="logo"></div>
      <span>fzy-blog</span>
    </a>
    <ul class="right-list">
      
        <li class="list-item">
          
            <a href="/" class="item-link">Home</a>
          
        </li>
      
        <li class="list-item">
          
            <a href="/tags/" class="item-link">Tags</a>
          
        </li>
      
        <li class="list-item">
          
            <a href="/archives/" class="item-link">Archives</a>
          
        </li>
      
        <li class="list-item">
          
            <a href="/project/" class="item-link">Projects</a>
          
        </li>
      
        <li class="list-item">
          
            <a href="/about/" class="item-link">About</a>
          
        </li>
      
    </ul>
    <div class="menu">
      <span class="icon-bar"></span>
      <span class="icon-bar"></span>
      <span class="icon-bar"></span>
    </div>
    <div class="menu-mask">
      <ul class="menu-list">
        
          <li class="menu-item">
            
              <a href="/" class="menu-link">Home</a>
            
          </li>
        
          <li class="menu-item">
            
              <a href="/tags/" class="menu-link">Tags</a>
            
          </li>
        
          <li class="menu-item">
            
              <a href="/archives/" class="menu-link">Archives</a>
            
          </li>
        
          <li class="menu-item">
            
              <a href="/project/" class="menu-link">Projects</a>
            
          </li>
        
          <li class="menu-item">
            
              <a href="/about/" class="menu-link">About</a>
            
          </li>
        
      </ul>
    </div>
  </div>
</header>

    <div id="article-banner">
  <h2>大型网站技术架构</h2>
  <p class="post-date">2019-05-24</p>
  <div class="arrow-down">
    <a href="javascript:;"></a>
  </div>
</div>
<main class="app-body flex-box">
  <!-- Article START -->
  <article class="post-article">
    <section class="markdown-content"><p>大型网站技术架构<br>早期的网站为了节省成本一般会设计成集中式系统，应用程序、数据库等都部署在一台服务器上。 但随着业务的快速度发展，逐渐出现瓶颈，按一定原则<strong>（应用拆分、服务拆分、数据拆分、应用解耦）</strong>，向分布式系统转型，涉及到以下环节改造。</p>
<p>主要环节<br>业务拆分：将整个网站业务拆分成不同的应用，每个应用独立部署维护，应用之间通过 RPC 或消息队列通信。<br>集群化（应用服务器；基于 RPC 的微服务应用等）<br>LVS 负载均衡，负责将请求转发给不同业务集群<br>反向代理服务器，常用的如 Nginx<br>应用服务器，servlet 容器，如 tomcat<br>应用和数据服务分离，分别部署在不同的服务器<br>后端应用合理分层，通常分为表现层或网关层、业务逻辑层、数据持久层<br>缓存。分为两种：本地缓存；分布式缓存<br>CDN 化。静态内容部署到 CDN，就近获取，加速网站响应。<br>数据库读写分离。数据库采用主从热备，应用服务器在写数据时访问主数据库，主数据库通过主从复制机制将数据更新同步到从数据库。<br>分库分表，引入分布式数据框架<br>引入 NoSQL，支持海量数据存储<br>借助 elastics search 等开源搜索引擎<br>异步化，系统解耦。<br>缩短业务流程，加快网站访问速度<br>消除并发访问高峰<br>架构五要素：<br>高性能<br>可用性(Availability)<br>伸缩性(Scalability)<br>扩展性(Extensibility)<br>安全性<br>1、高性能<br>性能的测试指标主要有：</p>
<p>响应时间：指应用执行一个操作需要的时间<br>并发数：指系统能够同时处理请求的数目<br>QPS：指单位时间内系统处理的请求量<br>系统性能计数器：描述服务器或者操作系统性能的一些数据指标<br>性能优化，根据网站分层架构，可以分为三大类：</p>
<p>Web 前端性能优化</p>
<p>减少 http 请求<br>使用浏览器缓存<br>启用压缩<br>CSS 放在页面最上面，JavaScript 放在页面最下面<br>减少 Cookie 传输<br>应用服务器性能优化：主要手段有 缓存、集群、异步</p>
<p>多线程(设计为无状态，使用局部对象，并发访问资源使用锁)<br>资源复用(单例，对象池)<br>数据结构<br>异步操作(消息队列，削峰作用)<br>多台应用服务器组成一个集群共同对外服务，提高整体处理能力。<br>使用 CDN，将网站静态内容分发至离用户最近的网络服务商机房，使用户通过最短访问路径获取数据。可以在网站机房部署反向代理服务器，缓存热点文件，加快请求响应速度，减轻应用服务器负载压力<br>应用服务器端，可以使用服务器本地缓存和分布式缓存(网站性能优化第一定律：优化考虑使用缓存优化性能)<br>代码层面，也可以通过使用多线程、改善内存管理等手段优化性能。<br>数据库服务器端，索引、缓存、SQL 优化等性能优化手段<br>NoSQL 数据库通过优化数据模型、存储结构、伸缩特性等<br>存储服务器性能优化</p>
<p>机械硬盘 vs. 固态硬盘<br>B+ 树 vs. LSM 树<br>RAID vs. HDFS<br>2、高可用<br>高可用的网站架构：目的是保证服务器硬件故障时服务依然可用、数据依然保存并能够被访问，主要手段数据和服务的冗余备份及失效转移</p>
<p>高可用的应用：显著特点是应用的无状态性<br>通过负载均衡进行无状态服务的失效转移<br>应用服务器集群的 Session 管理<br>高可用的服务：无状态的服务，可使用类似负载均衡的失效转移策略，此外还有如下策略<br>超时设置<br>异步调用<br>服务降级<br>限流<br>高可用的数据：主要手段是数据备份和失效转移机制<br>失效确认<br>访问转移<br>数据恢复<br>冷备：缺点是不能保证数据最终一致和数据可用性<br>热备：分为异步热备和同步热备<br>数据一致性(Consisitency)<br>数据可用性(Availibility)<br>分区耐受性(Partition Tolerance)<br>CAP 原理<br>数据备份<br>软件质量保证<br>自动化测试<br>预发布验证<br>灰度发布<br>网站实时监控<br>警报系统<br>自动优雅降级<br>用户行为日志采集（服务器端和客户端）<br>服务器性能监控<br>监控数据采集<br>监控管理<br>3、伸缩性<br>大型网站需要面对大量用户的高并发访问和存储海量数据，不可能只用一台服务器就处理全部用户请求，存储全部数据。网站通过集群的方式将多台服务器组成一个整体共同提供服务。所谓伸缩性是指通过不断向集群中加入服务器的手段来缓解不断上升的用户并发访问压力和不断增长的数据存储需求。</p>
<p>衡量架构伸缩性的主要标准就是是否可以用多台服务器构建集群，是否容易向集群中添加新的服务器。加入新的服务器后是否可以提供和原来的服务器无差别的服务。集群中可容纳的总的服务器数量是否有限制。</p>
<p>对于应用服务器集群，只要服务器上不保存数据，所有服务器都是对等的，通过使用合适的负载均衡设备就可以向集群中不断加入服务器。</p>
<p>对于缓存服务器集群，加入新的服务器可能会导致缓存路由失效，进而导致集群中大部分缓存数据都无法访问。虽然缓存的数据可以通过数据库重新预热，但是如果应用已经严重依赖缓存，可能会导致整个网站崩溃。需要改进缓存路由算法保证缓存数据的可访问性。</p>
<p>关系数据库虽然支持数据复制，主从热备等机制，但是很难做到大规模集群的可伸缩性，因此关系数据库的集群伸缩性方案必须在数据库之外实现，通过路由分区等手段将部署有多个数据库的服务器组成一个集群。</p>
<p>至于大部分 NoSQL 数据库产品，由于其先天就是为海量数据而生，因此其对伸缩性的支持通常都非常好，可以做到在较少运维参与的情况下实现集群规模的线性伸缩。</p>
<p>概括起来伸缩性的分为如下几个方面：</p>
<p>应用服务器集群的伸缩性设计<br>轮询(Round Robin, RR)<br>加权轮询(Weighted Round Robin, WRR)<br>随机(Random)<br>最少链接(Least Connections)<br>源地址散列(Source Hashing)<br>DNS 域名解析负载均衡<br>反向代理负载均衡(在 HTTP 协议层面，应用层负载均衡)<br>IP 负载均衡(在内核进程完成数据分发)<br>数据链路层负载均衡(数据链路层修改 mac 地址，三角传输模式，LVS)<br>分布式缓存集群的伸缩性设计<br>Memcached 客户端（包括 API，路由算法，服务器列表，通信模块）<br>Memcached 服务器集群<br>分布式缓存的一致性 Hash 算法(一致性 Hash 环，虚拟层)<br>数据存储服务集群的伸缩性设计<br>关系数据库集群的伸缩性设计<br>NoSQL 数据库的伸缩性设计<br>4、可扩展<br>系统架构设计层面的“开闭原则”，构建可扩展的网站架构</p>
<p>利用分布式消息队列降低耦合性<br>分布式消息队列<br>事件驱动架构(Event Driven Architecture)<br>利用分布式服务打造可复用的业务平台<br>分布式服务框架设计(Thrift，Dubbo)<br>可扩展的数据结构(如 HBase 的 ColumnFamily 设计)<br>利用开放平台建设网站生态圈<br>5、网站的安全架构<br>XSS 攻击和 SQL 注入攻击是构成网站应用攻击最主要的两种手段，此外还包括 CSRF,Session 劫持等手段。</p>
<p>攻击与防御<br>Error Code<br>表单 Token<br>验证码<br>jsonp 请求的，Referer 校验<br>SQL 注入<br>html 危险字符转义<br>XSS 攻击：跨站点脚本攻击（Cross Site Script）<br>对 js 转义，使其失去执行功能，只作为纯字符串展示</p>
<p>CSRF 攻击：跨站点请求伪造（Cross Site Request Forgery）<br>防范：httpOnly;增加 token 校验;通过 Referer 识别。</p>
<p>网站安全漏洞扫描<br>来源： <a href="https://github.com/aalansehaiyang/technology-talk/blob/master/system-architecture/大型网站技术架构.md" target="_blank" rel="noopener">https://github.com/aalansehaiyang/technology-talk/blob/master/system-architecture/大型网站技术架构.md</a></p>
</section>
    <!-- Tags START -->
    
    <div class="tags">
      <span>Tags:</span>
      
  <a href="/tags#分布式微服务架构">
    <span class="tag-code">分布式微服务架构</span>
  </a>

    </div>
    
    <!-- Tags END -->
    <!-- NAV START -->
    
  <div class="nav-container">
    <!-- reverse left and right to put prev and next in a more logic postition -->
    
      <a class="nav-left" href="/2019/05/24/分布式微服务架构/微服务架构/">
        <span class="nav-arrow">← </span>
        
          微服务架构
        
      </a>
    
    
      <a class="nav-right" href="/2019/05/24/分布式微服务架构/大型分布式电商系统架构是如何从0开始演进/">
        
          大型分布式电商系统架构是如何从0开始演进
        
        <span class="nav-arrow"> →</span>
      </a>
    
  </div>

    <!-- NAV END -->
    <!-- 打赏 START -->
    
    <div class="money-like">
      <div class="reward-btn">
        赏
        <span class="money-code">
          <span class="alipay-code">
            <div class="code-image"></div>
            <b>使用支付宝打赏</b>
          </span>
          <span class="wechat-code">
            <div class="code-image"></div>
            <b>使用微信打赏</b>
          </span>
        </span>
      </div>
      <p class="notice">若你觉得我的文章对你有帮助，欢迎点击上方按钮对我打赏</p>
    </div>
    
    <!-- 打赏 END -->
    <!-- 二维码 START -->
    
    <div class="qrcode">
      <canvas id="share-qrcode"></canvas>
      <p class="notice">扫描二维码，分享此文章</p>
    </div>
    
    <!-- 二维码 END -->
    
    <!-- No Comment -->
    
  </article>
  <!-- Article END -->
  <!-- Catalog START -->
  
  <aside class="catalog-container">
  <div class="toc-main">
    <strong class="toc-title">Catalog</strong>
    
      <ol class="nav">none</ol>
    
  </div>
</aside>
  
  <!-- Catalog END -->
</main>

<script>
  (function () {
    var url = 'https://fengzhaoy.github.io/2019/05/24/分布式微服务架构/大型网站技术架构/';
    var banner = ''
    if (banner !== '' && banner !== 'undefined' && banner !== 'null') {
      $('#article-banner').css({
        'background-image': 'url(' + banner + ')'
      })
    } else {
      $('#article-banner').geopattern(url)
    }
    $('.header').removeClass('fixed-header')

    // error image
    $(".markdown-content img").on('error', function () {
      $(this).attr('src', 'http://file.muyutech.com/error-img.png')
      $(this).css({
        'cursor': 'default'
      })
    })

    // zoom image
    $(".markdown-content img").on('click', function () {
      var src = $(this).attr('src')
      if (src !== 'http://file.muyutech.com/error-img.png') {
        var imageW = $(this).width()
        var imageH = $(this).height()

        var zoom = ($(window).width() * 0.95 / imageW).toFixed(2)
        zoom = zoom < 1 ? 1 : zoom
        zoom = zoom > 2 ? 2 : zoom
        var transY = (($(window).height() - imageH) / 2).toFixed(2)

        $('body').append('<div class="image-view-wrap"><div class="image-view-inner"><img src="' + src +
          '" /></div></div>')
        $('.image-view-wrap').addClass('wrap-active')
        $('.image-view-wrap img').css({
          'width': `${imageW}`,
          'transform': `translate3d(0, ${transY}px, 0) scale3d(${zoom}, ${zoom}, 1)`
        })
        $('html').css('overflow', 'hidden')

        $('.image-view-wrap').on('click', function () {
          $(this).remove()
          $('html').attr('style', '')
        })
      }
    })
  })();
</script>


<script>
  var qr = new QRious({
    element: document.getElementById('share-qrcode'),
    value: document.location.href
  });
</script>





    <div class="scroll-top">
  <span class="arrow-icon"></span>
</div>
    <footer class="app-footer">
  <p class="copyright">
    &copy; 2019
  </p>
</footer>

<script>
  function async (u, c) {
    var d = document,
      t = 'script',
      o = d.createElement(t),
      s = d.getElementsByTagName(t)[0];
    o.src = u;
    if (c) {
      o.addEventListener('load', function (e) {
        c(null, e);
      }, false);
    }
    s.parentNode.insertBefore(o, s);
  }
</script>
<script>
  async ("//cdnjs.cloudflare.com/ajax/libs/fastclick/1.0.6/fastclick.min.js", function () {
    FastClick.attach(document.body);
  })
</script>

<script>
  var hasLine = 'true';
  async ("//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/highlight.min.js", function () {
    $('figure pre').each(function (i, block) {
      var figure = $(this).parents('figure');
      if (hasLine === 'false') {
        figure.find('.gutter').hide();
      }
      var lang = figure.attr('class').split(' ')[1] || 'code';
      var codeHtml = $(this).html();
      var codeTag = document.createElement('code');
      codeTag.className = lang;
      codeTag.innerHTML = codeHtml;
      $(this).attr('class', '').empty().html(codeTag);
      figure.attr('data-lang', lang.toUpperCase());
      hljs.highlightBlock(block);
    });
  })
</script>
<!-- Baidu Tongji -->

<script src="/js/script.js"></script>
  </body>
</html>